package jp.ac.waseda.cs.washi.game.ai;

import jp.ac.waseda.cs.washi.game.api.*;
import jp.ac.waseda.cs.washi.game.entity.PumpkinCore;
import jp.ac.waseda.cs.washi.gameaiarena.api.Direction4;
import jp.ac.waseda.cs.washi.gameaiarena.api.Point2;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;


//新版
public class team2 implements Player{
	
	static MapInfo map;
	static CharaInfo mychara;
	static CharaInfo enemy;
	private static LinkedList<PlayerAction> commandList = new LinkedList<PlayerAction>();
	static int h,w;
	private static Direction4[] directions;

	// KingPumpkinを作るための一連の動きを表す配列
	static PlayerAction[] BIGbonusMakeActions = {PlayerAction.SPELL,
			PlayerAction.LEFT, PlayerAction.SPELL,
			PlayerAction.UP, PlayerAction.SPELL,
			PlayerAction.RIGHT,PlayerAction.SPELL,
			PlayerAction.RIGHT,PlayerAction.SPELL,
			PlayerAction.DOWN,PlayerAction.SPELL,
			PlayerAction.DOWN,PlayerAction.SPELL,
			PlayerAction.LEFT, PlayerAction.SPELL,
			PlayerAction.LEFT, PlayerAction.SPELL,
			PlayerAction.UP, PlayerAction.SPELL,
			PlayerAction.LEFT, PlayerAction.SPELL,
			PlayerAction.RIGHT, PlayerAction.RIGHT,PlayerAction.UP,PlayerAction.UP, PlayerAction.SPELL,
			PlayerAction.DOWN,PlayerAction.DOWN,PlayerAction.RIGHT, PlayerAction.RIGHT, PlayerAction.SPELL,
			PlayerAction.LEFT, PlayerAction.LEFT,PlayerAction.DOWN,PlayerAction.DOWN, PlayerAction.SPELL,			
	};
	
	static PlayerAction[] miniPumpkinActions = {
		PlayerAction.SPELL,PlayerAction.LEFT, PlayerAction.SPELL,
		PlayerAction.RIGHT,PlayerAction.UP,PlayerAction.SPELL,
		PlayerAction.DOWN,PlayerAction.RIGHT,	PlayerAction.SPELL,
		PlayerAction.LEFT,PlayerAction.DOWN,	 PlayerAction.SPELL,
	};

	Point2 findNearBigSpace(int n){
		//n:上限の距離
		Point2 p;
		for(int i=1;i<=n;i++){
			for(int j=0;j<i;j++){
				if(canMakeKingPumpkin((p=new Point2(mychara.getLocation().x-i+j,mychara.getLocation().y-j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakeKingPumpkin((p=new Point2(mychara.getLocation().x+j,mychara.getLocation().y-i+j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakeKingPumpkin((p=new Point2(mychara.getLocation().x+i-j,mychara.getLocation().y+j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakeKingPumpkin((p=new Point2(mychara.getLocation().x-j,mychara.getLocation().y+i-j))))
						return p;
			}
		}
		return null;
	}
	Point2 findNearSmallSpace(int n){
		//n:上限の距離
		Point2 p;
		for(int i=1;i<=n;i++){
			for(int j=0;j<i;j++){
				if(canMakePumpkin((p=new Point2(mychara.getLocation().x-i+j,mychara.getLocation().y-j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakePumpkin((p=new Point2(mychara.getLocation().x+j,mychara.getLocation().y-i+j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakePumpkin((p=new Point2(mychara.getLocation().x+i-j,mychara.getLocation().y+j))))
						return p;
			}
			for(int j=0;j<i;j++){
				if(canMakePumpkin((p=new Point2(mychara.getLocation().x-j,mychara.getLocation().y+i-j))))
						return p;
			}
		}
		return null;
	}

	void destroy(){
		ArrayList<PumpkinInfo> pump = enemy.getPumpkins();
		if(pump.size()!=0){
			List<PumpkinCore> cores = pump.get(0).getCores();
			if (cores.size() == 0)
				return;
			else {
				PumpkinCore core = cores.get(0);
				Point2 p = core.getLocation();
				moveTo(p);
				commandList.add(PlayerAction.SPELL);
			}
		}
	}
	
	public PlayerAction execute(GameInfo gameInfo) {
		// ゲーム環境から最新の情報を取得します。
		map = gameInfo.getMap();
		mychara = gameInfo.getPlayer();
		enemy = gameInfo.getEnemy();

		//コマンドリストにコマンドがあった場合、逐次そのコマンドを実行する
		if (commandList.size() != 0) {
			if(commandList.getFirst()==PlayerAction.SPELL){
				if(map.getRequiredDevelopCount(mychara, mychara.getLocation())>1){
					return PlayerAction.SPELL;
				}
			}
			return commandList.remove(0);
		}else{
			Point2 ppp=findNearBigSpace(20);
			if(ppp!=null)
				MakeBigPumpkin(ppp);
			else if((ppp=findNearSmallSpace(20))!=null){
				MakePumpkin(ppp);
			}else{
				destroy();
			}
		}
		return null;
	}

	void MakeBigPumpkin(Point2 p){
		moveTo(p);
		for(int i=0;i<BIGbonusMakeActions.length;i++)
			commandList.add(BIGbonusMakeActions[i]);
		return;
	}
	void MakePumpkin(Point2 p){
		moveTo(p);
		for(int i=0;i<miniPumpkinActions.length;i++)
			commandList.add(miniPumpkinActions[i]);
		return;
	}

	//指定された位置からキングパンプキンを作成可能かどうかを返すメソッド
	public static boolean canMakeKingPumpkin(Point2 p) {
		if (!map.isMovable(p))
			return false;
		//検索位置移動用の配列
		int x[]={ 0, 0,0,0,0,-1,-1,-1,-2, 1,1,1,2,};
		int y[]={-2,-1,0,1,2,-1, 0, 1, 0,-1,0,1,0,};
	
		int xx[]={-3,-2,-2,-1,-1,0, 0,1, 1,2, 2,3,};
		int yy[]={ 0, 1,-1, 2,-2,3,-3,2,-2,1,-1,0,};

		Point2 dp;

		for (int i = 0; i < x.length; i++) {
			dp = p.add(new Point2(x[i], y[i]));
			if(map.isAvailable(dp))
				if (!map.canDevelop(dp)|| !map.isMovable(dp))
					return false;
		}		
		for (int i = 0; i < xx.length; i++) {
			dp = p.add(new Point2(xx[i], yy[i]));
			if(map.isAvailable(dp))
				if (map.getOwner(dp) == mychara)
					return false;
		}
		
		return true;
	}

	//指定された位置からパンプキンを作成可能かどうかを返すメソッド
	public static boolean canMakePumpkin(Point2 p) {
		if (!map.isMovable(p))
			return false;
		//検索位置移動用の配列
		int x[]={ 0,0,0,-1,1,};
		int y[]={-1,0,1, 0,0,};
	
		int xx[]={-2,-1,-1,0, 0,1, 1,2,};
		int yy[]={ 0,-1, 1,2,-2,1,-1,0,};

		Point2 dp;

		for (int i = 0; i < x.length; i++) {
			dp = p.add(new Point2(x[i], y[i]));
			if(map.isAvailable(dp))
				//if (map.getOwner(dp) != null || !map.canDevelop(dp)|| !map.isMovable(dp))
				if (!map.canDevelop(dp)|| !map.isMovable(dp))
					return false;
		}		
		for (int i = 0; i < xx.length; i++) {
			dp = p.add(new Point2(xx[i], yy[i]));
			if(map.isAvailable(dp))
				if (map.getOwner(dp) == mychara)
					return false;
		}		
		return true;
	}

	//現在位置から指定位置へ移動するコマンドをcommandListに追加するメソッド
	public static void moveTo(Point2 p) {
		directions = map.getPath(mychara.getLocation(), p);
		for (Direction4 dir : directions)
			commandList.add(PlayerAction.fromDirection(dir));
		return;
	}
	
	public void initialize(GameInfo gameInfo) {
		map = gameInfo.getMap();
		mychara = gameInfo.getPlayer();
		enemy = gameInfo.getEnemy();
		h=map.getHeight();
		w=map.getWidth();
	}

	// プレイヤーを指定してゲームをスタートします。
	public static void main(String[] args) {
		GameInvoker.startForDebug(new team2(),new KingPumpkinMaker(), 5);
	}
}
